/*****************************************************************
Wowengine - v0.1

File: wen_node.cpp
Creation date: 2012-10-15
*****************************************************************/
#include "wen_node.h"
#include <iostream>

using namespace wen;

Node::Node()
:
Spatial()
{
	m_pkComposeBV = new BVH();
}

Node::~Node()
{
	RemoveAllChilds(true);
}

int Node::AddChild(Spatial* child)
{
	if(!child)
	{
		return -1;
	}

	unsigned int theIndex = 0;
	bool canAdd = true;

	if(!m_childrenVector.empty())
	{
		vector<Spatial*>::iterator iter = m_childrenVector.begin();

		for(; iter != m_childrenVector.end(); iter++)
		{
			if((*iter) == child)
			{
				canAdd = false;
				break;
			}
			theIndex++;
		}		
	}

	if(canAdd)
	{
		m_childrenVector.push_back(child);
		child->SetParent(this);
	}

	return theIndex;
}

Spatial* Node::GetChildAt(unsigned int index)
{
	if(index >= m_childrenVector.size())
	{
		return NULL;
	}

	return m_childrenVector[index];
}

unsigned int Node::GetChildCount() const 
{
	return (unsigned int)m_childrenVector.size(); 
}

vector<Spatial*>& Node::GetAllChildren()
{
	return m_childrenVector; 
}

void Node::RemoveChild(Spatial* child, bool withCleanUp)
{
	if(!child || m_childrenVector.empty())
	{
		return;
	}
	
	vector<Spatial*>::iterator iter = m_childrenVector.begin();

	for(; iter != m_childrenVector.end(); iter++)
	{
		if((*iter) == child)
		{
			m_childrenVector.erase(iter);

			if(withCleanUp)
			{
				delete (*iter);
				(*iter) = NULL;				
			}
			else
			{
				(*iter)->SetParent(NULL); 
			}
			break;
		}		
	}		
}

Spatial* Node::RemoveChildAt(unsigned int index, bool withCleanUp)
{
	Spatial* tmpSpatial = NULL;

	if(m_childrenVector.empty() || index >= m_childrenVector.size())
	{
		return tmpSpatial;
	}

	unsigned int theIndex = 0;
	
	vector<Spatial*>::iterator iter = m_childrenVector.begin();

	for(; iter != m_childrenVector.end(); iter++)
	{
		if(theIndex == index)
		{
			m_childrenVector.erase(iter);

			if(withCleanUp)
			{
				delete (*iter);
				(*iter) = NULL;
			}
			else
			{
				(*iter)->SetParent(NULL);
				tmpSpatial = (*iter);
			}
			break;
		}
		theIndex++;
	}

	return tmpSpatial;
}

Spatial* Node::GetChildByName(const std::string& name)
{
	vector<Spatial*>::iterator iter = m_childrenVector.begin();

	if(type == TYPE_NODE && GetName().compare(name) == 0)
	{
		return this;
	}

	for(; iter != m_childrenVector.end(); iter++)
	{
		int theType = (*iter)->type;

		std::string theName = (*iter)->GetName();

		if(theType == TYPE_NODE)
		{
			Node* tmpNode = (Node*)(*iter);

			if(tmpNode->GetName().compare(name) == 0)
			{
				return (*iter);
			}
			else
			{
				return tmpNode->GetChildByName(name);
			}
		}

		if((*iter)->GetName().compare(name) == 0)
		{
			return (*iter);
		}
	}

	return NULL;
}

void Node::RemoveAllChilds(bool withCleanUp)
{
	for(unsigned int i = 0; i < m_childrenVector.size(); i++)
	{
		if(withCleanUp)
		{
			delete m_childrenVector[i];
			m_childrenVector[i] = NULL;
		}
		else
		{
			m_childrenVector[i]->SetParent(NULL);
		}
	}	
	m_childrenVector.clear();
}

void Node::Update(float fTimeBetweenFrames)
{
	if(m_bVisible)
	{
		Spatial::Update(fTimeBetweenFrames);

		for(unsigned int i = 0; i < m_childrenVector.size(); i++)
		{
			m_childrenVector[i]->Update(fTimeBetweenFrames);
		}
	}
}

void Node::Draw(Render& rkRender)
{
	Spatial::Draw(rkRender);

	//UpdateBoundingVolume(rkRender);

	//m_bVisible = CheckBVHFrustumCollision(m_pkComposeBV, rkRender);

	if(m_bVisible)
	{
		std::string nodeName = GetName();
		std::cout << nodeName << "\n";

		//Spatial::Draw(rkRender);

		for(unsigned int i = 0; i < m_childrenVector.size(); i++)
		{
			m_childrenVector[i]->Draw(rkRender);
		}
	}

	//if(m_pkParent)
	//	m_pkParent->UpdateBoundingVolume(rkRender);

	if(!m_pkParent)
		UpdateBoundingVolume(rkRender);
}

void Node::UpdateBoundingVolume(Render& rkRender)
{
	for(unsigned int i = 0; i < m_childrenVector.size(); i++)
	{
		Spatial* sp = m_childrenVector[i];
		if (sp->type == TYPE_MESH)
		{
			//BVH* original = sp->GetBVH();
			sp->CalculateBVH(rkRender);
			
			D3DXVECTOR3 lclXYZ;
			lclXYZ.x = sp->GetBVH()->m_iMaxX;
			lclXYZ.y = sp->GetBVH()->m_iMaxY;
			lclXYZ.z = sp->GetBVH()->m_iMaxZ;
			D3DXVECTOR3 XYZ;
			D3DXVec3TransformCoord(&XYZ, &lclXYZ, &m_worldTransform);

			D3DXVECTOR3 lclxyz;
			lclxyz.x = sp->GetBVH()->m_iMinX;
			lclxyz.y = sp->GetBVH()->m_iMinY;
			lclxyz.z = sp->GetBVH()->m_iMinZ;
			D3DXVECTOR3 xyz;
			D3DXVec3TransformCoord(&xyz, &lclxyz, &m_worldTransform);

			if(	xyz.x < this->GetBVH()->m_iMinX)
				this->GetBVH()->m_iMinX = xyz.x;
			if(	xyz.y < this->GetBVH()->m_iMinY)
				this->GetBVH()->m_iMinY = xyz.y;
			if(	xyz.z < this->GetBVH()->m_iMinZ)
				this->GetBVH()->m_iMinZ = xyz.z;
			if(	XYZ.x > this->GetBVH()->m_iMaxX)
				this->GetBVH()->m_iMaxX = XYZ.x;
			if(	XYZ.y > this->GetBVH()->m_iMaxY)
				this->GetBVH()->m_iMaxY = XYZ.y;
			if(	XYZ.z > this->GetBVH()->m_iMaxZ)
				this->GetBVH()->m_iMaxZ = XYZ.z;
		}
	}

	for(unsigned int i = 0; i < m_childrenVector.size(); i++)
	{	
		Spatial* sp = m_childrenVector[i];
		if (sp->type == TYPE_NODE)
		{
			sp->UpdateBoundingVolume(rkRender);
		}
	}

	for(unsigned int i = 0; i < m_childrenVector.size(); i++)
	{	
		Spatial* sp = m_childrenVector[i];
		if (sp->type == TYPE_NODE)
		{	
			if( sp->GetBVH()->m_iMinX < this->GetBVH()->m_iMinX)
				this->GetBVH()->m_iMinX = sp->GetBVH()->m_iMinX;
			if(	sp->GetBVH()->m_iMinY < this->GetBVH()->m_iMinY)
				this->GetBVH()->m_iMinY = sp->GetBVH()->m_iMinY;
			if(	sp->GetBVH()->m_iMinZ < this->GetBVH()->m_iMinZ)
				this->GetBVH()->m_iMinZ = sp->GetBVH()->m_iMinZ;
			if(	sp->GetBVH()->m_iMaxX > this->GetBVH()->m_iMaxX)
				this->GetBVH()->m_iMaxX = sp->GetBVH()->m_iMaxX;
			if(	sp->GetBVH()->m_iMaxY > this->GetBVH()->m_iMaxY)
				this->GetBVH()->m_iMaxY = sp->GetBVH()->m_iMaxY;
			if(	sp->GetBVH()->m_iMaxZ > this->GetBVH()->m_iMaxZ)
				this->GetBVH()->m_iMaxZ = sp->GetBVH()->m_iMaxZ;
		}
	}

	/*for(int i = 0; i < m_childrenVector.size(); i++)
	{
		Spatial* sp = m_childrenVector[i];
		if (sp->type == TYPE_MESH)
		{
			BVH* original = sp->GetBVH();
			original->TransformBVHVertex(&m_worldTransform);
			sp->SetTransformedBVH(original);

			m_TransformedBVHVertices.push_back(original->GetMaxVertex());
			m_TransformedBVHVertices.push_back(original->GetMinVertex());
		}
	}

	for(int i = 0; i < m_childrenVector.size(); i++)
	{
		Spatial* sp = m_childrenVector[i];
		if (sp->type == TYPE_NODE)
		{
			sp->UpdateBoundingVolume(rkRender);
			
			BVH* nodeBVH = sp->GetBVH();

			m_TransformedBVHVertices.push_back(nodeBVH->GetMaxVertex());
			m_TransformedBVHVertices.push_back(nodeBVH->GetMinVertex());
		}
	}
	
	float maxX = -99999.0f;
	float minX = 99999.0f;
	float maxY = -99999.0f;
	float minY = 99999.0f;
	float maxZ = -99999.0f;
	float minZ = 99999.0f;

	for (int i = 0; i < m_TransformedBVHVertices.size(); i++)
	{
		D3DXVECTOR3* vect = m_TransformedBVHVertices[i];
		if (vect->x > maxX)
		{
			maxX = vect->x;
		}
		
		if (vect->x < minX)
		{
			minX = vect->x;
		}
		
		if (vect->y > maxY)
		{
			maxY = vect->y;
		}
		
		if (vect->y < minY)
		{
			minY = vect->y;
		}

		if (vect->z > maxZ)
		{
			maxZ = vect->z;
		}
		
		if (vect->z < minZ)
		{
			minZ = vect->z;
		}
	}
	m_pkComposeBV->SetBVHBoxVertices(maxX, minX, maxY, minY, maxZ, minZ);
	m_TransformedBVHVertices.clear();*/

	////
	//Calcular el BoundignVolume del nodo
	//tomar los maximos y minimos de todos los hijos
	//de todos esos valores, sacar cual es el maximo y minimo total
	//transformar esos nuevos valores
	/*float maxX = -999999.0f;
	float minX = 999999.0f;
	float maxY = -999999.0f;
	float minY = 999999.0f;
	float maxZ = -999999.0f;
	float minZ = 999999.0f;

	for(unsigned int i = 0; i < m_childrenVector.size(); i++)
	{
		Spatial* sp = m_childrenVector[i];

		if (sp->GetBVH() == NULL)
			continue;

		if (sp->type == TYPE_NODE)
		{
			sp->UpdateBoundingVolume(rkRender);
		}

		D3DXVECTOR3* maxVertex = sp->GetBVH()->GetMaxVertex();
		D3DXVECTOR3* minVertex = sp->GetBVH()->GetMinVertex();

		if (maxVertex == NULL || minVertex == NULL)
			continue;

		if (maxVertex->x > maxX)
		{
			maxX = maxVertex->x;
		}
		
		if (maxVertex->y > maxY)
		{
			maxY = maxVertex->y;
		}
		
		if (maxVertex->z > maxZ)
		{
			maxZ = maxVertex->z;
		}

		if (minVertex->x < minX)
		{
			minX = minVertex->x;
		}
		
		if (minVertex->y < minY)
		{
			minY = minVertex->y;
		}

		if (minVertex->z < minZ)
		{
			minZ = minVertex->z;
		}
	}

	m_pkComposeBV->SetBVHBoxVertices(maxX, minX, maxY, minY, maxZ, minZ);
	
	m_pkComposeBV->TransformBVHVertex(&m_worldTransform);*/
}